{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## VQ-VAE MNIST"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torchvision\n",
    "import torch.nn as nn\n",
    "import torch.optim as optim\n",
    "from torchvision import transforms\n",
    "from tqdm import tqdm\n",
    "\n",
    "# Define the transformations to apply to the data\n",
    "transform = transforms.Compose([\n",
    "    transforms.ToTensor(),\n",
    "    transforms.Normalize((0.5,), (0.5,))\n",
    "])\n",
    "\n",
    "# Load the MNIST dataset\n",
    "train_dataset = torchvision.datasets.MNIST(root='~/data', train=True, download=True, transform=transform)\n",
    "test_dataset = torchvision.datasets.MNIST(root='~/data', train=False, download=True, transform=transform)\n",
    "\n",
    "# Create the data loaders\n",
    "batch_size = 256\n",
    "train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\n",
    "test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size, shuffle=False)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define the VQ-VAE encoder\n",
    "class Encoder(nn.Module):\n",
    "    def __init__(self, input_dim, hidden_dim, embedding_dim):\n",
    "        super(Encoder, self).__init__()\n",
    "        self.conv1 = nn.Conv2d(input_dim, hidden_dim, kernel_size=4, stride=2, padding=1)\n",
    "        self.conv2 = nn.Conv2d(hidden_dim, hidden_dim, kernel_size=4, stride=2, padding=1)\n",
    "        self.conv3 = nn.Conv2d(hidden_dim, embedding_dim, kernel_size=1, stride=1)\n",
    "        \n",
    "    def forward(self, x):\n",
    "        x = torch.relu(self.conv1(x))\n",
    "        x = torch.relu(self.conv2(x))\n",
    "        x = self.conv3(x)\n",
    "        return x\n",
    "\n",
    "# Define the VQ-VAE decoder\n",
    "class Decoder(nn.Module):\n",
    "    def __init__(self, embedding_dim, hidden_dim, output_dim):\n",
    "        super(Decoder, self).__init__()\n",
    "        self.deconv1 = nn.ConvTranspose2d(embedding_dim, hidden_dim, kernel_size=4, stride=2, padding=1)\n",
    "        self.deconv2 = nn.ConvTranspose2d(hidden_dim, hidden_dim, kernel_size=4, stride=2, padding=1)\n",
    "        self.deconv3 = nn.ConvTranspose2d(hidden_dim, output_dim, kernel_size=1, stride=1)\n",
    "        \n",
    "    def forward(self, x):\n",
    "        x = torch.relu(self.deconv1(x))\n",
    "        x = torch.relu(self.deconv2(x))\n",
    "        x = self.deconv3(x)\n",
    "        x = torch.tanh(x)\n",
    "        return x\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Quantizer(nn.Module):\n",
    "    def __init__(self, num_embeddings, embedding_dim):\n",
    "        super(Quantizer, self).__init__()\n",
    "        # codebook vectors \n",
    "        self.embedding = nn.Embedding(num_embeddings, embedding_dim)\n",
    "        # w/o this line, training will not converge\n",
    "        self.embedding.weight.data.uniform_(-1./num_embeddings, 1./num_embeddings)\n",
    "        self.embedding_dim = embedding_dim\n",
    "        self.num_embeddings = num_embeddings\n",
    "        \n",
    "    def forward(self, z_e):\n",
    "        # z_e - encoder latent code (B, C, H, W) -> (B, H, W, C)\n",
    "        z_e = z_e.permute(0, 2, 3, 1).contiguous()\n",
    "        z_e_shape = z_e.shape\n",
    "        # flat version of z_e\n",
    "        flat_z_e = z_e.view(-1, self.embedding_dim)\n",
    "\n",
    "        # distance between z_e and embeddings\n",
    "        distances = (torch.sum(flat_z_e**2, dim=1, keepdim=True) \n",
    "                    + torch.sum(self.embedding.weight**2, dim=1)\n",
    "                    - 2 * torch.matmul(flat_z_e, self.embedding.weight.t()))\n",
    "        \n",
    "        # minimal distance between z_e and embeddings\n",
    "        encoding_indices = torch.argmin(distances, dim=1).unsqueeze(1)\n",
    "        encodings = torch.zeros(encoding_indices.shape[0], self.num_embeddings, device=z_e.device)\n",
    "        # one-hot vector based on the minimal distance (eg 49 x 10-dimensional one-hot vectors)\n",
    "        encodings.scatter_(1, encoding_indices, 1)\n",
    "        \n",
    "        # Quantize and unflatten\n",
    "        # N one-hot encodings quantizing/filtering by 0 or 1 each dim (col) of embedding\n",
    "        # The encodings builds a map of which feature point of each feature embedding vector is used\n",
    "        z_q = torch.matmul(encodings, self.embedding.weight).view(z_e_shape)\n",
    "        \n",
    "        # What is the purpose of z_q + (z_e - z_q).detach()?\n",
    "        # Preserve gradients?\n",
    "        z_q = z_e + (z_q - z_e).detach()\n",
    "        \n",
    "        # restore to original channel dimension\n",
    "        z_q = z_q.permute(0, 3, 1, 2).contiguous()\n",
    "\n",
    "        return z_q, encoding_indices"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {},
   "outputs": [],
   "source": [
    "class VQVAE(nn.Module):\n",
    "    def __init__(self, input_dim, hidden_dim, embedding_dim, num_embeddings):\n",
    "        super(VQVAE, self).__init__()\n",
    "        \n",
    "        self.encoder = Encoder(input_dim, hidden_dim, embedding_dim)\n",
    "        self.quantizer = Quantizer(num_embeddings, embedding_dim)\n",
    "        self.decoder = Decoder(embedding_dim, hidden_dim, input_dim)\n",
    "        \n",
    "    def forward(self, x):\n",
    "        # Encode the input\n",
    "        z_e = self.encoder(x)\n",
    "        \n",
    "        # Quantize the encoded input\n",
    "        z_q, indices = self.quantizer(z_e)\n",
    "        \n",
    "        # Decode the quantized input\n",
    "        x_hat = self.decoder(z_q)\n",
    "        \n",
    "        return x_hat, z_e, z_q, indices\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {},
   "outputs": [],
   "source": [
    "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
    "model = VQVAE(1, 128, 64, 10).to(device)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [],
   "source": [
    "random_input = torch.randn(1, 1, 28, 28).to(device)\n",
    "z_e = model.encoder(random_input)\n",
    "z_q, indeces = model.quantizer(z_e)\n",
    "x_hat = model.decoder(z_q)\n",
    "#x_hat, z_e, z_q, indices = model(random_input)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of parameters: 666945\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 10%|█         | 1/10 [00:09<01:24,  9.35s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch [1/10], Ave Loss: 0.0132,        Recon Loss: 0.0004, Commit Loss: 0.0106, Latent Loss: 0.0106\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 20%|██        | 2/10 [00:18<01:13,  9.24s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch [2/10], Ave Loss: 0.0232,        Recon Loss: 0.0002, Commit Loss: 0.0191, Latent Loss: 0.0191\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 30%|███       | 3/10 [00:27<01:04,  9.22s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch [3/10], Ave Loss: 0.0327,        Recon Loss: 0.0002, Commit Loss: 0.0271, Latent Loss: 0.0271\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 40%|████      | 4/10 [00:36<00:55,  9.22s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch [4/10], Ave Loss: 0.0392,        Recon Loss: 0.0002, Commit Loss: 0.0325, Latent Loss: 0.0325\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 50%|█████     | 5/10 [00:46<00:46,  9.27s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch [5/10], Ave Loss: 0.0464,        Recon Loss: 0.0002, Commit Loss: 0.0385, Latent Loss: 0.0385\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 60%|██████    | 6/10 [00:55<00:36,  9.24s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch [6/10], Ave Loss: 0.0520,        Recon Loss: 0.0002, Commit Loss: 0.0432, Latent Loss: 0.0432\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 70%|███████   | 7/10 [01:04<00:27,  9.22s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch [7/10], Ave Loss: 0.0537,        Recon Loss: 0.0002, Commit Loss: 0.0446, Latent Loss: 0.0446\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 80%|████████  | 8/10 [01:13<00:18,  9.20s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch [8/10], Ave Loss: 0.0529,        Recon Loss: 0.0002, Commit Loss: 0.0439, Latent Loss: 0.0439\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 90%|█████████ | 9/10 [01:23<00:09,  9.25s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch [9/10], Ave Loss: 0.0571,        Recon Loss: 0.0002, Commit Loss: 0.0474, Latent Loss: 0.0474\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 10/10 [01:32<00:00,  9.23s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch [10/10], Ave Loss: 0.0607,        Recon Loss: 0.0002, Commit Loss: 0.0504, Latent Loss: 0.0504\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "# Set the number of epochs\n",
    "num_epochs = 10\n",
    "\n",
    "# Create an optimizer\n",
    "optimizer = optim.Adam(model.parameters())\n",
    "# Print the number of parameters\n",
    "print(f\"Number of parameters: {sum(p.numel() for p in model.parameters() if p.requires_grad)}\")\n",
    "\n",
    "# Train the model\n",
    "for epoch in tqdm(range(num_epochs)):\n",
    "    total_loss = 0\n",
    "    r_loss = 0\n",
    "    c_loss = 0\n",
    "    l_loss = 0  \n",
    "    total = 0 \n",
    "    for batch_idx, (data, _) in enumerate(train_loader):\n",
    "        # Move the data to the device\n",
    "        data = data.to(device)\n",
    "        total += data.size(0)\n",
    "        \n",
    "        # Forward pass\n",
    "        x_hat, z_e, z_q, indices = model(data)\n",
    "        recon_loss = nn.MSELoss()(x_hat, data)\n",
    "        commit_loss = nn.MSELoss()(z_e.detach(), z_q)\n",
    "        latent_loss = nn.MSELoss()(z_e, z_q.detach())\n",
    "        loss = recon_loss + 0.2 * commit_loss + latent_loss\n",
    "        \n",
    "        # Backward pass\n",
    "        optimizer.zero_grad()\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "        \n",
    "        total_loss += loss.item()\n",
    "        r_loss += recon_loss.item()\n",
    "        c_loss += commit_loss.item()\n",
    "        l_loss += latent_loss.item()\n",
    "    \n",
    "    tqdm.write(f\"Epoch [{epoch+1}/{num_epochs}], Ave Loss: {total_loss/total:.4f},\\\n",
    "        Recon Loss: {r_loss/total:.4f}, Commit Loss: {c_loss/total:.4f}, Latent Loss: {l_loss/total:.4f}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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2LFjIuvXr581Hj9+fFjPnR4uv/xykW3evFlkW7du9XE4USceSs01+/btE5l7YwetmLpbt24io+j8HyVLlhRZnTp1/B+Io2fPniKbNm2ayJKSkqzxDTfcIOY0atQo0Nd8++23rbG25uLZkiVLrPHRo0fFnDx58oisTZs2InNvFhNJ1113ncgOHz4csefXbnh10UXy80ZHjhyxxtFanM8npQAAAAAAAOAdm1IAAAAAAADwjk0pAAAAAAAAeMemFAAAAAAAALyj6Dwd1apVK+zHli5d2hpnz549tYeDc3j00UdDzjl+/LjItm3bFtbX0woU3bJ1Y2SpbPv27cWc3bt3h3UMiA0PPfSQNW7dunXYzzV69GhrrJUWI20UK1ZMZMWLFxfZqlWrRHbmzJmIHYd7vvjmm2/EHC3TymjnzZtnjfPmzSvmuMXqxlB0HimZM2cW2X333SeyZ599VmRaUarr1KlTIhswYIDIRo0aFfK5ooH2Hso9JxpjzOuvvy6ycePGpcUhIYOpUKGCyAoXLiyyeC211n4ncn/XSWu1a9cWmVbor1273nzzTWusnW+zZJG/du/Zs0dksXLeTC8LFy60xlqh+PTp00VWoECBiB3DyZMnRXbrrbda46+//jpiX0+7AckVV1whMq24/ZdffonYcaQlPikFAAAAAAAA79iUAgAAAAAAgHdsSgEAAAAAAMA7OqU8KleunDXu3bu3mJMpUyaRaf0O7t8ba3+TDH8GDRokssOHD4d83NVXXy2y+vXriywlJUVkbqfHb7/9FvLrIXZpa2XIkCFhPZe2NseMGRPWcyH1PvroI5FpXQH9+/cX2aRJk6zxzp07I3dgATVr1kxkR48eDfk4rZfjzz//jMgxxTutn2X48OERe/5evXqJbMKECRF7/rR2/fXXW+MePXqIOVr/yMqVK9PqkJDBjR8/XmTJycnpcCTRqXnz5iLTfidyab8jab06iYmJIvvkk0+s8d133x3oGK655hqR1ahR43yHeU4DBw4U2YkTJ8J6rng1f/58kb3zzjsi07o627Zta4219yBan+fLL78ssh07dpz3OFND6w3WuiMPHjwosjfeeCMtDini+KQUAAAAAAAAvGNTCgAAAAAAAN6xKQUAAAAAAADv2JQCAAAAAACAdzFfdK4VpT744IPWuFChQmKOVji4YsWKsI4hf/78ItMKRS+/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efPmtcba90g7F7h9P8bI90dZs2YVc7QOIE2WLPbbzCDdeMbo79tc2bNnF5l2HezatavI3n777Qv+evHEXQOPPfaYmKN9/8eMGSMy972v9v7+0KFDItu0aZPI3n//fWusdfRo7720XiC3O0brldWOVft5oFMqumivm8Y9v2q/G2o9r1pf8vTp062x9r59xYoVIuP9tj/aucF93zx06FAxR+sQ064Z7u9lGzZsEHN+/vlnkX3wwQci+/33362x1mGV0fBJKQAAAAAAAHjHphQAAAAAAAC8Y1MKAAAAAAAA3rEpBQAAAAAAAO+ipujcderUKZFNmDBBZFrxV5DSuNOnT4tMK0z8/PPPrfENN9wg5mgFxEFL9pAxaGW0WuHqE088YY21Qmst0wpFly5dao0rVaok5hQuXFhk69atExn8cddKqVKlxJyBAweKrGHDhiIrXry4NdbWnFbK+vDDD4vMXT/PPvusmPPXX3+JTENxZ+pphZxa5pZtusXSxujnj5IlS4qsZs2a1vjKK68Uc2666SaRaTcJcdeAdk13S0HP9Vxu+ezJkyfFHO29gHYufeCBB6zx/PnzxZxt27aJLL0E/VlyfzbbtGkj5miF30WKFBGZe04qWrSomDNz5kyRaV+zWbNm1rhQoUJijrautWuqWyatvb7a47Tnxz+070+ePHmscfPmzcWcAQMGiGzBggUic99va9cprThae08e7o0KtCJyd61s2bJFzNHKjIPeVAHRzy2wvuOOO8Qc7YZa2vXsyy+/tMbuDYSMkeX6SDvuOcwYY1q0aCGykSNHWmP3piHnot2oxf2atWvXFnOqVasmsnbt2onMPZd++umnYo52A7jDhw+LTFuv0YgrNQAAAAAAALxjUwoAAAAAAADesSkFAAAAAAAA79iUAgAAAAAAgHdRW3SulRlqpajh0spDtfLCzZs3W+NffvlFzLnnnntE1rJly5DPpZW1IjZp5cJaOaxbcKcV5Wnl5I888ojIcubMaY3z588v5mjP36tXL5G98cYb1li7EQAunHZOyZcvnzXWSjS1GypoheVuubNW5qq9ltpzuYXEnTt3FnO0Y9XOY8nJySLDhdHKh7XrlvtaVq9eXczRSjTvvPNOkZUrV84aa+cP7TqsFRK7x6X9LGjnLO253POr9r3Rzpva2i9QoEDIORmhGPvAgQMimzRpksi077f7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AAAA4B2bUgAAAAAAAPCOTSkAAAAAAAB4x6YUAAAAAAAAvIvaovOMyC0RC1qmphVf58+f3xpr5XmLFi0S2alTp0QW68V44dIKDbWSvfr161tjrXTPLTA3xpg1a9aE/Jra19OK1N3yPO25tNJgrVAvXl/vWBek0LV06dJiTu3atUV20UXy/yNmzZpljb/++msxJx4KWNOD9npo52q3+NIYWcTrFu4ao5+ztPNfjhw5Qs7R1kC2bNlE1qRJE2t88cUXizlz584VmXbeDLfsG6Fp5wy3pFl7D/L555+LTHvt3Pc98XD9CVq0HUu0ElzfpebGhP991B7nnnfd858x+vlOOzdPmzbNGmul5vXq1RPZJ598IrJ4ValSJZFpN1lw39No10/tmqFl27dvt8azZ88Wc+bNmycy9/2SMfJarBW3azeZyZJF/iq+fv16a5wRS8012nsJ7fXdtm2bNR4wYICY8+KLL4qsSpUqIuvXr5811m4StnXrVpH16NFDZO7NYX777TcxZ86cOSLbu3evyHLlymWNGzVqJOa4v58ao79v27RpkzXWitWj4X0Wn5QCAAAAAACAd2xKAQAAAAAAwDs2pQAAAAAAAOAdm1IAAAAAAADwLm6LzrXSwyClceE+zhhjsmfPbo3bt28v5mhFi1mzZhXZX3/9ZY1///33QMelFcZpBZbxSvteV6tWzRprJXLa998tljNGFg5rBYdu6Z4xxpQtW1ZkR44cscY///yzmKO9ttoa0P5NiC7auSchIcEajx49WswpWbKkyLRC4hEjRljj5OTkCz1EhEl7jbSC3aNHj4pMK911aecB7fqglam6tHVYsGBBkdWoUcMaawWvV155pci0cykunHaeL1++vMh69+4tMrfYfMWKFWKOVuAa5GYMQd+XBCm0Dnrd0p7ffT9WoEABMadMmTIiK168uMgWLFhgjbUCcK6x5xd0DQRZF9oNIbTMfb+nXfO049K460m7uYR205FYL8APl/b9CXIdMUa+bto10C0dN0a/pi5btswaazeI2rJlS8hjMMaYunXrWmOtaLtx48Yi096P3X333dY4I5aaa2tf+zkNcu7UXrcdO3aITLvhinsjKW09aTezcovIjZG/m8+fP1/MWb58uciC3NhGuwlWzpw5RXbo0CGRuTfA0YrVowGflAIAAAAAAIB3bEoBAAAAAADAOzalAAAA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",
      "text/plain": [
       "<Figure size 1200x600 with 32 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([16, 64, 7, 7])\n",
      "index: 1\n",
      "tensor(-7.2635, device='cuda:0', grad_fn=<SumBackward0>)\n",
      "index: 2\n",
      "tensor(-6.4684, device='cuda:0', grad_fn=<SumBackward0>)\n",
      "index: 3\n",
      "tensor(-7.2977, device='cuda:0', grad_fn=<SumBackward0>)\n",
      "index: 4\n",
      "tensor(-7.8611, device='cuda:0', grad_fn=<SumBackward0>)\n",
      "index: 5\n",
      "tensor(-5.3653, device='cuda:0', grad_fn=<SumBackward0>)\n",
      "index: 6\n",
      "tensor(-9.1054, device='cuda:0', grad_fn=<SumBackward0>)\n",
      "index: 7\n",
      "tensor(-5.1085, device='cuda:0', grad_fn=<SumBackward0>)\n",
      "index: 8\n",
      "tensor(-4.6867, device='cuda:0', grad_fn=<SumBackward0>)\n",
      "index: 9\n",
      "tensor(-7.1445, device='cuda:0', grad_fn=<SumBackward0>)\n",
      "index: 10\n",
      "tensor(-4.9817, device='cuda:0', grad_fn=<SumBackward0>)\n",
      "index: 11\n",
      "tensor(-9.6027, device='cuda:0', grad_fn=<SumBackward0>)\n",
      "index: 12\n",
      "tensor(-6.9829, device='cuda:0', grad_fn=<SumBackward0>)\n",
      "index: 13\n",
      "tensor(-10.1071, device='cuda:0', grad_fn=<SumBackward0>)\n",
      "index: 14\n",
      "tensor(-3.3657, device='cuda:0', grad_fn=<SumBackward0>)\n",
      "index: 15\n",
      "tensor(-7.8205, device='cuda:0', grad_fn=<SumBackward0>)\n",
      "index: 16\n",
      "tensor(-8.1888, device='cuda:0', grad_fn=<SumBackward0>)\n"
     ]
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "model.eval()\n",
    "\n",
    "# Get 16 random samples from the test split\n",
    "random_indices = torch.randint(0, len(test_dataset), (16,))\n",
    "samples = [test_dataset[i][0] for i in random_indices]\n",
    "\n",
    "# Move the samples to the device\n",
    "samples = torch.stack(samples).to(device)\n",
    "\n",
    "reconstructed_samples, _, _, _ = model(samples)\n",
    "\n",
    "# Denormalize the samples\n",
    "samples = (samples * 0.5) + 0.5\n",
    "reconstructed_samples = (reconstructed_samples * 0.5) + 0.5\n",
    "\n",
    "# Visualize the original and reconstructed images\n",
    "fig, axes = plt.subplots(4, 8, figsize=(12, 6))\n",
    "axes = axes.flatten()\n",
    "\n",
    "for i in range(16):\n",
    "    axes[i].imshow(samples[i].squeeze().cpu(), cmap='gray')\n",
    "    axes[i].axis('off')\n",
    "    axes[i+16].imshow(reconstructed_samples[i].squeeze().detach().cpu(), cmap='gray')\n",
    "    axes[i+16].axis('off')\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "x_hat, z_e, z_q, indices = model(samples)\n",
    "print(z_q.shape)\n",
    "for i in range(16):\n",
    "    print(f\"index: {i+1}\")\n",
    "    print(torch.sum(z_q[i]))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([0.0582, 0.0582, 0.0582,  ..., 0.0667, 0.0055, 0.0055], device='cuda:0',\n",
      "       grad_fn=<ViewBackward0>)\n",
      "tensor([ 0.0582,  0.0200, -0.0752,  ...,  0.0332,  0.0172,  0.0055],\n",
      "       device='cuda:0', grad_fn=<ViewBackward0>)\n",
      "torch.Size([3136])\n",
      "torch.Size([3136])\n",
      "tensor(-7.2635, device='cuda:0', grad_fn=<SumBackward0>)\n",
      "tensor(-7.1445, device='cuda:0', grad_fn=<SumBackward0>)\n"
     ]
    }
   ],
   "source": [
    "a = z_q[0]\n",
    "b = z_q[8]\n",
    "a = a.view(-1)\n",
    "b = b.view(-1)\n",
    "print(a)\n",
    "print(b)\n",
    "print(a.shape)\n",
    "print(b.shape)\n",
    "print(torch.sum(a))\n",
    "print(torch.sum(b))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "fuyu",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
